#include "uart_v1.hpp"

#include <glog/logging.h>
uart_v1::uart_v1(std::string port_name,
                 int baud_rate,
                 int data_bits,
                 int stop_bits) : _port_name(port_name),
                                  _baud_rate(baud_rate),
                                  _data_bits(data_bits),
                                  _stop_bits(stop_bits)
{
    open_flag = SP_ERR_FAIL;
}

sp_return uart_v1::uart_open()
{
    sp_return ret;
    if (open_flag == SP_OK)
    {
        LOG(ERROR) << "[uart_v1][uart_open][port_name: " << _port_name << "]:" << "uart has been opened";
        return SP_ERR_FAIL;
    }

    ret = sp_get_port_by_name(_port_name.c_str(), &_port);
    if (ret != SP_OK)
    {
        LOG(ERROR) << "[uart_v1][uart_open][port_name: " << _port_name << "]:" << sp_last_error_message();
        open_flag = SP_ERR_FAIL;
        goto end;
    }
    ret = sp_open(_port, SP_MODE_READ_WRITE);
    if (ret != SP_OK)
    {
        LOG(ERROR) << "[uart_v1][uart_open][port_name: " << _port_name << "]:" << sp_last_error_message();
        open_flag = SP_ERR_FAIL;
        goto end;
    }

    LOG(INFO) << "[uart_v1][uart_open][port_name: " << _port_name << "]:" << "uart opened";
    sp_set_baudrate(_port, _baud_rate);
    sp_set_bits(_port, _data_bits);
    sp_set_parity(_port, SP_PARITY_NONE);
    sp_set_stopbits(_port, _stop_bits);
    sp_set_flowcontrol(_port, SP_FLOWCONTROL_NONE);

    open_flag = SP_OK;

    _byte_timeout_ms = 10 * 1000 / _baud_rate ;//*10 可略微增大字节超时时间，防止读取数据时出现超时
    if (_byte_timeout_ms < 20)
        _byte_timeout_ms = 20;
    uart_print_config();

end:

    return ret;
}



uart_v1::~uart_v1()
{
    uart_close();
    sp_free_port(_port);
}

sp_return uart_v1::uart_close()
{
    sp_return ret = sp_close(_port);
    if (ret != SP_OK)
    {
        LOG(ERROR) << "[uart_v1][uart_close][port_name: " << _port_name << "]:" << sp_last_error_message();
    }
    return ret;
}

int uart_v1::uart_send(const uint8_t *data, int len)
{
    if (open_flag != SP_OK || !data)
    {
        LOG(ERROR) << "[uart_v1][uart_send][port_name: " << _port_name << "]:" << "uart not open";
        return 0;
    }
    // int delay_ms = (len * 10) * 1000 / _baud_rate * 1.5;
    int bytes_written = sp_blocking_write(_port, data, len,2000);

    // while(sp_output_waiting(_port) != 0)
    // {
    //     std::this_thread::sleep_for(std::chrono::milliseconds(1));
    // }
    std::this_thread::sleep_for(std::chrono::milliseconds(2000));

    return bytes_written;
}

int uart_v1::uart_recv(uint8_t *data, int len)
{
    uint32_t time_out = 0;
    if (open_flag != SP_OK || !data)
    {
        LOG(ERROR) << "[uart_v1][uart_recv][port_name: " << _port_name << "]:" << "uart not open";
        return 0;
    }
    while(sp_input_waiting(_port) < len && time_out < 10000)//10s超时
    {
        std::this_thread::sleep_for(std::chrono::milliseconds(2));
        time_out += 2;
    }
    if(time_out >= 10000)
    {
        uart_flush_all();
        LOG(ERROR) << "[uart_v1][uart_recv][port_name: " << _port_name << "]:" << "uart recv timeout";
        return 0;
    }
    int bytes_read = sp_nonblocking_read(_port, data, len);
    return bytes_read;
}

int uart_v1::uart_recv_one_by_one(uint8_t *data, int max_len, int frame_timeout_ms)
{
    if (open_flag != SP_OK || !data)
    {
        LOG(ERROR) << "[uart_v1][uart_recv_one_by_one][port_name: " << _port_name << "]:" << "uart not open";
        return 0;
    }
    int offset = 0;
    int bytes_read = 0;
    bytes_read = sp_blocking_read(_port, data + offset, 1, frame_timeout_ms);
    if (bytes_read == 0)
    {
        return 0;
    }
    
    offset++;
    while (1)
    {

        
        bytes_read = sp_blocking_read(_port, data + offset, 1, _byte_timeout_ms);
        // int bytes_read = sp_nonblocking_read(_port, data + offset, 1);
        if (bytes_read == 0)
            break;

        if (offset + 1 >= max_len  )
        {
            LOG(WARNING) << "[uart_v1][uart_recv_one_by_one][port_name: " << _port_name << "]:" << "mem overflow but still can recv data";
            break;
        }

        offset++;
    }

    return offset ;
}

std::string uart_v1::uart_get_port_name()
{
    return _port_name;
}

void uart_v1::uart_change_baud_rate(int baud_rate)
{
    if(baud_rate == _baud_rate)
        return;
    
    sp_set_baudrate(_port, baud_rate);
    _byte_timeout_ms = 10 * 1000 / baud_rate ;//*10 可略微增大字节超时时间，防止读取数据时出现超时
    if (_byte_timeout_ms == 0)
    _byte_timeout_ms = 1;
    _baud_rate = baud_rate;
}

void uart_v1::uart_flush_all()
{
    sp_flush(_port, SP_BUF_BOTH);
}

void uart_v1::uart_print_config()
{
    LOG(INFO) << "[uart_v1][uart_config][port_name: " << _port_name << "]:\n"
              << "baudrate: " << _baud_rate << "\n"
              << "data_bits: " << _data_bits << "\n"
              << "stop_bits: " << _stop_bits << "\n"
              << "byte_timeout_ms: " << _byte_timeout_ms << "\n"
              << "open_flag: " << open_flag << "\n";
}
